﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace WentStateMachine
{
    public static class ExtendStateMachine
    {
        public static bool ContainState(this StateMachine stateMachine, State state)
        {
            return stateMachine.States.Contains(state);
        }

        public static State FindStateByName(this StateMachine stateMachine, string name)
        {
            return stateMachine.FindStateByHash(Helper.ScriptingStringToCRC32(name));
        }

        public static int FindStateIndexByName(this StateMachine stateMachine, string name)
        {
            return stateMachine.FindStateIndexByHash(Helper.ScriptingStringToCRC32(name));
        }

        public static List<int> FindStateReferenceByName(this StateMachine stateMachine, string name)
        {
            return stateMachine.FindStateReferenceByHash(Helper.ScriptingStringToCRC32(name));
        }

        //FIXME 与 FindStateMachineReferenceByHash 功能不一致
        public static List<int> FindStateMachineReferenceByName(this StateMachine stateMachine, string name)
        {
            var hash = Helper.ScriptingStringToCRC32(name);
            if(stateMachine.nameHash == hash)
            {
                return new List<int>() { -1 };
            }
            return stateMachine.FindStateMachineReferenceByHash(hash);
        }

        public static State FindStateByHash(this StateMachine stateMachine, int hash)
        {
            if (stateMachine.States == null)
                return null;

            var len = stateMachine.States.Length;
            for (int i = 0; i < len; i++)
            {
                if (stateMachine.States[i].IsHash(hash))
                    return stateMachine.States[i];
            }
            return null;
        }

        public static int FindStateIndexByHash(this StateMachine stateMachine, int hash)
        {
            if (stateMachine.States == null)
                return -1;

            var len = stateMachine.States.Length;
            for (int i = 0; i < len; i++)
            {
                if (stateMachine.States[i].IsHash(hash))
                    return i;
            }
            return -1;
        }

        public static List<int> FindStateReferenceByHash(this StateMachine stateMachine, int hash, List<int> result = null)
        {
            if (stateMachine.States == null)
                return null;

            if (result == null)
                result = new List<int>();

            var len = stateMachine.States.Length;
            for (int i = 0; i < len; i++)
            {
                if (stateMachine.States[i].IsHash(hash))
                {
                    result.Add(i);
                    return result;
                }
            }

            len = stateMachine.ChildStateMachine.Length;
            for(int i = 0; i < len; i++)
            {
                var ret = stateMachine.ChildStateMachine[i].FindStateReferenceByHash(hash, result);
                if (ret != null)
                {
                    result.Add(i);
                    return result;
                }
            }

            return null;
        }

        public static List<int> FindStateMachineReferenceByHash(this StateMachine stateMachine, int hash, List<int> result = null)
        {
            if (stateMachine.ChildStateMachine == null)
                return null;

            if (result == null)
                result = new List<int>();

            var len = stateMachine.ChildStateMachine.Length;
            for (int i = 0; i < len; i++)
            {
                if (stateMachine.ChildStateMachine[i].nameHash == hash)
                {
                    result.Add(i);
                    return result;
                }
            }

            for (int i = 0; i < len; i++)
            {
                var ret = stateMachine.ChildStateMachine[i].FindStateMachineReferenceByHash(hash, result);
                if (ret != null)
                {
                    result.Add(i);
                    return result;
                }
            }

            return null;
        }

        public static State FindStateByHashInChildren(this StateMachine stateMachine, int hash, StateMachine toSkil = null)
        {
            if (stateMachine.ChildStateMachine == null)
                return null;

            var len = stateMachine.ChildStateMachine.Length;
            for(int i = 0; i < len; i++)
            {
                var result = stateMachine.ChildStateMachine[i].FindStateByHash(hash);
                if (result != null)
                    return result;
            }
            for (int i = 0; i < len; i++)
            {
                var result = stateMachine.ChildStateMachine[i].FindStateByHashInChildren(hash, toSkil);
                if (result != null)
                    return result;
            }
            return null;
        }

        public static StateMachine FindStateMachineByName(this StateMachine stateMachine, string name)
        {
            return stateMachine.FindStateMachineByHash(Helper.ScriptingStringToCRC32(name));
        }

        public static StateMachine FindStateMachineByHash(this StateMachine stateMachine, int hash)
        {
            if (stateMachine.nameHash == hash)
            {
                return stateMachine;
            }
            else
            {
                if (stateMachine.ChildStateMachine == null)
                    return null;
                foreach(var child in stateMachine.ChildStateMachine)
                {
                    var result = child.FindStateMachineByHash(hash);
                    if (result != null)
                        return result;
                }
            }
            return null;
        }

        public static void DoInChildrenStateMachine(this StateMachine stateMachine, Action<StateMachine> action)
        {
            if (stateMachine.ChildStateMachine == null)
                return;
            foreach(var child in stateMachine.ChildStateMachine)
            {
                action(child);
            }

            foreach (var child in stateMachine.ChildStateMachine)
            {
                child.DoInChildrenStateMachine(action);
            }
        }
    }
}
